package com.org.cloud.lg.api;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.org.cloud.lg.utils.BaseContextKit;
import com.org.cloud.lg.utils.DozerUtils;
import com.org.cloud.lg.utils.SnowflakeIdWorker;
import com.org.cloud.lg.model.BaseModel;
import com.org.cloud.lg.model.PageDto;
import com.org.cloud.lg.utils.Checker;
import javafx.scene.chart.Chart;
import org.apache.commons.lang3.StringUtils;
import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class MBaseServiceImpl<D ,T extends BaseModel,M extends BaseMapper<T>> extends ServiceImpl<M, T> implements MBaseService<D>{

    @Autowired
    Mapper dozerMapper;

	@Autowired
	protected M MbMapper;

	protected Class<T> tclz;

    protected Class<D> dclz;

    protected List<String> select(){ return null; };

	protected String getUserId(){
		return BaseContextKit.getUserID();
	}


	protected List<D> T2DList(List<T> list){
		return DozerUtils.T2DList(dozerMapper,list,dclz);
	}

	protected List<T> D2TList(List<D> list){
		return DozerUtils.D2TList(dozerMapper,list,tclz);
	}

    protected String generateId(){
    	return SnowflakeIdWorker.getId();
	}

    protected QueryWrapper<T> condition(T t) { return null; };

    public MBaseServiceImpl(){
        Type genType = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        dclz = (Class<D>) params[0];
        tclz = (Class<T>) params[1];
    }


	@Override
	public List<D> listDto(D d) {
        T t=D2T(d);
        QueryWrapper<T> queryWrapper= wrapperIt(t);
        List<T> list=super.list(queryWrapper);
        if (Checker.BeEmpty(list))
        return Lists.newArrayList();
        return DozerUtils.T2DList(dozerMapper,list,dclz);
	}

	@Override
	public List<D> listDtoByMap(Map<String, Object> map) {
    	List<T> list= (List<T>) super.listByMap(map);
		if (Checker.BeEmpty(list)) return Lists.newArrayList();
		return DozerUtils.T2DList(dozerMapper,list,dclz);
	}

	@Override
	public PageDto<D> listPage(PageDto<D> d) {
        T t=D2T(d.getDto());
        QueryWrapper<T> queryWrapper= wrapperIt(t);
        Page<T> page = new Page<T>(d.getPageNo(),d.getPageSize());
        IPage<T> pageRes = super.page(page, queryWrapper);
        if(Checker.BeEmpty(pageRes.getRecords())){
            return new PageDto<>(0,Lists.newArrayList());
        }
        List<D> dlist =DozerUtils.T2DList(dozerMapper,pageRes.getRecords(),dclz);
        long count = pageRes.getTotal();
        return  new PageDto<>(count,pageRes.getPages(),pageRes.getCurrent(),dlist);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean insert(D d) {
        Date date=new Date();
        T t=D2T(d);
        t.setGmtCreate(date).setGmtModified(date).setCreateId(BaseContextKit.getUserID()).
        setId(Checker.BeNotBlank(t.getId())?t.getId():SnowflakeIdWorker.getId());
        return super.save(t);
	}

	@Override
	public boolean insertBatch(List<D> dtos) {
		List<T> dlist =DozerUtils.D2TList(dozerMapper,dtos,tclz);
		Date date=new Date();
		if(Checker.BeNotEmpty(dlist)){
			dlist.forEach(dclz->{
				dclz.setGmtCreate(date);
			});
		}
		return super.saveBatch(dlist);
	}

	@Override
	@Transactional
	public boolean updateByPk(D d) {
        Date date=new Date();
        T t=D2T(d);
        t.setGmtModified(date).setModifiedId(BaseContextKit.getUserID());
		return super.updateById(t);
	}

    @Override
    public D getByPk(Serializable pk) {
         T t=super.getById(pk);
         return Checker.BeNotNull(t)?T2D(t):null;
    }

	@Override
	@Transactional
	public boolean deleteByPk(String id) {
		return super.removeById(id);
	}

	@Override
	public boolean deleteByPks(List<String> ids) {
		return super.removeByIds(ids);
	}

	@Override
	public D getOneDto(D d) {
        QueryWrapper<T> queryWrapper= wrapperIt(D2T(d));
        T t=super.getOne(queryWrapper);
        return Checker.BeNotNull(t)?T2D(t):null;
	}

	@Override
	public D getOneByMap(Map<String, Object> param) {
		List<D> dtos=listDtoByMap(param);
		return Checker.BeNotEmpty(dtos)?dtos.get(0):null;
	}


	protected T D2T(D d){
        return dozerMapper.map(d, tclz);
    }

    protected D T2D(T t){
        return dozerMapper.map(t, dclz);
    }

	private QueryWrapper<T> wrapperIt(T t) {
		if (Checker.BeNull(t)) {
			return new QueryWrapper<>(t);
		}
		QueryWrapper<T> wrapper = null;
		wrapper = condition(t);
		if (Checker.BeNull(wrapper)) {
			wrapper = new QueryWrapper<T>();
			autoCondition(wrapper,t);
		}
		List<String> cmns = select();
		if (Checker.BeNotNull(cmns)) {
			wrapper.select(StringUtils.join(cmns.toArray(),","));
		}
		return wrapper;
	}
	
	

	private void autoCondition(QueryWrapper<T>  wrapper,T t){
		Field[] files=t.getClass().getDeclaredFields();
	    for(Field file:files){
			try {
				 file.setAccessible(true);
				 if(Checker.BeNotNull(file.get(t))&&Checker.BeNotBlank(file.get(t).toString())){
					 TableField tableFile=file.getAnnotation(TableField.class);
					 TableId tableId=file.getAnnotation(TableId.class);
					 if(Checker.BeNotNull(tableFile)&&tableFile.exist()==false){//忽略字段
						 continue;
					 }
					 if(Checker.BeNotNull(tableId)){//主键
						 wrapper.eq((Checker.BeBlank(tableId.value())?file.getName():tableId.value()), file.get(t));
					 }else{//非主键的情况
					 	 if(Checker.BeNotNull(tableFile)){
							 if(String.class.isAssignableFrom(file.getType())){
								 wrapper.like((Checker.BeNotBlank(tableFile.value())?tableFile.value():file.getName()),file.get(t).toString());
							 }
							 if(isNumClass(file.getType())){
								 wrapper.eq((Checker.BeNotBlank(tableFile.value())?tableFile.value():file.getName()), file.get(t));
							 }
						 }
					 }
				 }
			} catch (IllegalArgumentException | IllegalAccessException e) {
				e.printStackTrace();
			}
	    }
	}

	private boolean isNumClass(Class<?> classzz){
		return (Number.class.isAssignableFrom(classzz));
	}


//	protected Cache getCache(String cacheName) {
//		if(Checker.BeNotBlank(cacheName))
//		return cacheManager.getCache(cacheName);
//		else
//	    return cacheManager.getCache("bootcache");
//	}

}
